<?php


namespace app\common\helpers;
define('EARTH_RADIUS', 6378.137);//地球半径
define('PI', 3.1415926);


use yii\httpclient\Client;
use  yii\httpclient\Clientl;
use yii\helpers\ArrayHelper;
use yii\helpers\Json;

class MapUtil
{
    public static function GetPortByAdress($adress){
        $result=self::getLocation($adress);
        return self::gcj2wgs($result[0],$result[1]);
    }

    /**
     * @param $addr
     * @return array
     * @throws \yii\base\InvalidConfigException
     * 根据地址获取经纬度
     */
    private static function getLocation($address){
        /**
         * 在生产环境无法使用外网使用转发获取数据的坐标
         */
        $method = "GET";
        $url = "http://restapi.amap.com/v3/geocode/geo?output=json&key=" . Config('amapKey') . '&address=' . $address;
        $headers = [];
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HEADER, false);
//        if (isset(\Yii::$app->params['curl_proxy']) && !empty(\Yii::$app->params['curl_proxy'])) {
//            curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
//            curl_setopt($curl, CURLOPT_PROXY, \Yii::$app->params['curl_proxy']);//'192.168.213.32:8888'
//        }
        $data = curl_exec($curl);
        curl_close($curl);
        $data = json_decode($data, true);
        if (isset($data['status'])) {
            if ($data['status'] == 1 && ArrayHelper::getValue($data, 'geocodes', false)) {
                return $data['geocodes'][0]['location'];
            }
        }
//
//        $client = new Client();
//        $data = $client->createRequest()
//            ->setMethod("GET")
//            ->setUrl("http://restapi.amap.com/v3/geocode/geo")
//            ->setData(["output" => "json","key" => \Yii::$app->params["amapKey"],"address" => $address])
//            ->send();
//
//        if ($data->isOk){
//            $data = Json::decode($data->content);
//            if($data['status'] == 1 && ArrayHelper::getValue($data,'geocodes',false)){
//                $loc = $data['geocodes'][0]['location'];
//                return explode(',',$loc);
//            }
//        }
         return [0,0];
    }


    /**
     * @param $longitude
     * @param $latitude
     * @return mixed
     * @throws \yii\base\InvalidConfigException
     * 根据经纬度获取地址
     */
    public static function getAdress($longitude,$latitude){
        $local="$longitude,$latitude";

        $method = "GET";
        $url = "http://restapi.amap.com/v3/geocode/regeo?output=json&key=" . Config('amapKey') . '&location=' . $local;
        $headers = [];
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HEADER, false);
//        if (isset(\Yii::$app->params['curl_proxy']) && !empty(\Yii::$app->params['curl_proxy'])) {
//            curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
//            curl_setopt($curl, CURLOPT_PROXY, \Yii::$app->params['curl_proxy']);//'192.168.213.32:8888'
//        }
        $data = curl_exec($curl);
        curl_close($curl);
        $data = json_decode($data, true);
        if (isset($data['status'])) {
            if ($data['status'] == 1 && isset($data['regeocode'])) {
                return $data['regeocode']['formatted_address'];
            }
        }
        return '';
//        $client = new Client();
//        $data = $client->createRequest()
//            ->setMethod("GET")
//            ->setUrl("http://restapi.amap.com/v3/geocode/regeo")
//            ->setData(["output" => "json","key" => \Yii::$app->params["amapKey"],"location" => $local])
//            ->send();
//        if ($data->isOk){
//            $data = Json::decode($data->content);
//            if($data['status'] == 1 && ArrayHelper::getValue($data,'regeocode',false)){
//                return $data['regeocode']['formatted_address'];
//            }
//        }
//        return '';
    }


    //将高德坐标转为火星坐标
    public static function gcj2wgs($lng,$lat){
        $coordinate = new Coordinate($lng,$lat);
        $coord = CoordinateTool::gcj_wgs($coordinate);
        return [$coord->x,$coord->y];
    }
    //百度转火星
    function bdGcj($lng,$lat) {
        $coordinate = new Coordinate($lng,$lat);
        $coord = (new CoordinateTool)->bd_gcj($coordinate);
        return [$coord->x,$coord->y];
    }


    /**
     * 计算两个点的距离
     * @param $lat1
     * @param $lon1
     * @param $lat2
     * @param $lon2
     * @param float $radius
     * @return float|int
     */
    public static function distance($lat1, $lon1, $lat2,$lon2,$radius = 6378.137)
    {
        $rad = floatval(M_PI / 180.0);

        $lat1 = floatval($lat1) * $rad;
        $lon1 = floatval($lon1) * $rad;
        $lat2 = floatval($lat2) * $rad;
        $lon2 = floatval($lon2) * $rad;

        $theta = $lon2 - $lon1;

        $dist = acos(sin($lat1) * sin($lat2) + cos($lat1) * cos($lat2) * cos($theta));

        if ($dist < 0 ) {
            $dist += M_PI;
        }
        return $dist = $dist * $radius;
    }
    public static function InArea(array $area,$lng,$lat){
        $min_lng=min(array_column($area,"lng"));
        $max_lng=max(array_column($area,"lng"));
        $min_lat=min(array_column($area,"lat"));
        $max_lat=max(array_column($area,"lat"));
        if($lat>=$min_lat&&$lat<=$max_lat&&$lng>=$min_lng&&$lng<=$max_lng){
            return true;
        }
        return false;
    }
    public static function ComputeLocationLine(array $location_point_list){
        $result=[];
        if(count($location_point_list)<2){
            return $location_point_list;
        }
        if(count($location_point_list)>20){
            $size=ceil(count($location_point_list)/15);//切割次数
            $location_point_new=[];
            $location_point_list[]=$location_point_list[0];
            $list=array_chunk($location_point_list,$size);
            foreach ($list as $value){
                $location_point_new[]=$value[0];
            }
            $location_point_new[]=$location_point_list[count($location_point_list)-1];
            $location_point_list=$location_point_new;
        }
        $start=implode(",",$location_point_list[0]);
        $end=implode(",",$location_point_list[count($location_point_list)-1]);
        if(count($location_point_list)>2) {
            $list=[];
            foreach ($location_point_list as $key=>$value){
                if($key==0&&$key==count($location_point_list)-1){
                    continue;
                }
                $list[]=implode(",",$value);
            }
            $pass_point=implode(";",$list);
            $url = "http://restapi.amap.com/v3/direction/driving?key=a41422c09e7ae30c883620669df34545&origin={$start}&destination={$end}&waypoints={$pass_point}&cartype=1&strategy=18";
        }else{
            $url = "http://restapi.amap.com/v3/direction/driving?key=a41422c09e7ae30c883620669df34545&origin={$start}&destination={$end}&cartype=1&strategy=18";
        }

        $method = "GET";
        $headers = array();
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HEADER, false);
        if(isset(\Yii::$app->params['curl_proxy']) && !empty(\Yii::$app->params['curl_proxy'])){
            curl_setopt($curl, CURLOPT_PROXYTYPE,CURLPROXY_HTTP);
            curl_setopt($curl, CURLOPT_PROXY,\Yii::$app->params['curl_proxy'] );//'192.168.213.32:8888'
        }
        $data = curl_exec($curl);
        curl_close($curl);

        $data=json_decode($data,true)['route']['paths'];
    //    return $data;
//        $data= (new ProxyCurl())
//            ->get($url);
    //    $data=json_decode($data,true)['route']['paths'];
//        print_r($data);die();
        foreach ($data as $datum){
            foreach ($datum['steps'] as $item){
                foreach (explode(";",$item['polyline']) as $value){
                    $location=explode(",",$value);
                    $location=self::gcj2wgs($location[0],$location[1]);
                    $result[]=$location;
                }
            }
//            $result[]=explode(";",$datum['polyline']);
        }
        return $result;
    }
    public static function GetDistanceV2($lat1, $lng1, $lat2, $lng2, $len_type = 1, $decimal = 2)
    {
        $radLat1 = $lat1 * PI / 180.0;
        $radLat2 = $lat2 * PI / 180.0;
        $a = $radLat1 - $radLat2;
        $b = ($lng1 * PI / 180.0) - ($lng2 * PI / 180.0);
        $s = 2 * asin(sqrt(pow(sin($a/2),2) + cos($radLat1) * cos($radLat2) * pow(sin($b/2),2)));
        $s = $s * EARTH_RADIUS;
        $s = round($s * 1000);
        if ($len_type > 1)
        {
            $s /= 1000;
        }
        return round($s, $decimal);
    }
    public static function GetCenterFromDegrees($data){

        if (!is_array($data)) return FALSE;

        $num_coords = count($data);

        $X = 0.0;
        $Y = 0.0;
        $Z = 0.0;

        foreach ($data as $coord){

            $lat = deg2rad((float)$coord[0]);
            $lon = deg2rad((float)$coord[1]);

            $a = cos($lat) * cos($lon);
            $b = cos($lat) * sin($lon);
            $c = sin($lat);

            $X += $a;
            $Y += $b;
            $Z += $c;
        }

        $X /= $num_coords;
        $Y /= $num_coords;
        $Z /= $num_coords;

        $lon = atan2($Y, $X);
        $hyp = sqrt($X * $X + $Y * $Y);
        $lat = atan2($Z, $hyp);

        return array(rad2deg($lat), rad2deg($lon));
    }
    /**
     * @param $points
     * @return array|bool
     * 计算一个围栏中的中心点
     */
    public static function calculateCenter($points,$ignore = false){
        $X = 0;$Y = 0;$Z = 0;
        foreach ($points as $item){
            $lng = $item['lng'] * pi() / 180;
            $lat = $item['lat'] * pi() / 180;
            $x = cos($lat) * cos($lng);
            $y = cos($lat) * sin($lng);
            $z = sin($lat);
            $X += $x;$Y += $y;$Z += $z;
        }

        $X = $X/count($points);
        $Y = $Y/count($points);
        $Z = $Z/count($points);

        $Lng = atan2($Y,$X);
        $Hyp  = sqrt($X*$X + $Y*$Y);
        $Lat = atan2($Z,$Hyp);

        $res = [
            'lng' => $Lng*180/pi(),
            'lat' => $Lat*180/pi()
        ];

        if ($ignore){
            return $res;
        }

        if (self::is_point_in_polygon($res,$points)){
            return $res;
        }

        return false;
    }
    /**
     * 判断一个坐标是否在一个多边形内（由多个坐标围成的）
     * 基本思想是利用射线法，计算射线与多边形各边的交点，如果是偶数，则点在多边形外，否则
     * 在多边形内。还会考虑一些特殊情况，如点在多边形顶点上，点在多边形边上等特殊情况。
     * @param array $point 指定点坐标 ["lng" => '',"lat" => ""]
     * @param $pts 多边形坐标 顺时针方向
     * $pts => [
     *      [
     *          "lng" => "float(31.180320004287)",
     *          "lat" => "float(31.180320004287)"
     *      ]
     * ]
     */
    public static function is_point_in_polygon($point, $pts) {
        $N = count($pts);
        $boundOrVertex = true; //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
        $intersectCount = 0;//cross points count of x
        $precision = 2e-10; //浮点类型计算时候与0比较时候的容差
        $p1 = 0;//neighbour bound vertices
        $p2 = 0;
        $p = $point; //测试点

        $p1 = $pts[0];//left vertex
        for ($i = 1; $i <= $N; ++$i) {//check all rays
            // dump($p1);
            if ($p['lng'] == $p1['lng'] && $p['lat'] == $p1['lat']) {
                return $boundOrVertex;//p is an vertex
            }

            $p2 = $pts[$i % $N];//right vertex
            if ($p['lat'] < min($p1['lat'], $p2['lat']) || $p['lat'] > max($p1['lat'], $p2['lat'])) {//ray is outside of our interests
                $p1 = $p2;
                continue;//next ray left point
            }

            if ($p['lat'] > min($p1['lat'], $p2['lat']) && $p['lat'] < max($p1['lat'], $p2['lat'])) {//ray is crossing over by the algorithm (common part of)
                if($p['lng'] <= max($p1['lng'], $p2['lng'])){//x is before of ray
                    if ($p1['lat'] == $p2['lat'] && $p['lng'] >= min($p1['lng'], $p2['lng'])) {//overlies on a horizontal ray
                        return $boundOrVertex;
                    }

                    if ($p1['lng'] == $p2['lng']) {//ray is vertical
                        if ($p1['lng'] == $p['lng']) {//overlies on a vertical ray
                            return $boundOrVertex;
                        } else {//before ray
                            ++$intersectCount;
                        }
                    } else {//cross point on the left side
                        $xinters = ($p['lat'] - $p1['lat']) * ($p2['lng'] - $p1['lng']) / ($p2['lat'] - $p1['lat']) + $p1['lng'];//cross point of lng
                        if (abs($p['lng'] - $xinters) < $precision) {//overlies on a ray
                            return $boundOrVertex;
                        }

                        if ($p['lng'] < $xinters) {//before ray
                            ++$intersectCount;
                        }
                    }
                }
            } else {//special case when ray is crossing through the vertex
                if ($p['lat'] == $p2['lat'] && $p['lng'] <= $p2['lng']) {//p crossing over p2
                    $p3 = $pts[($i+1) % $N]; //next vertex
                    if ($p['lat'] >= min($p1['lat'], $p3['lat']) && $p['lat'] <= max($p1['lat'], $p3['lat'])) { //p.lat lies between p1.lat & p3.lat
                        ++$intersectCount;
                    } else {
                        $intersectCount += 2;
                    }
                }
            }
            $p1 = $p2;//next ray left point
        }

        if ($intersectCount % 2 == 0) {//偶数在多边形外
            return false;
        } else { //奇数在多边形内
            return true;
        }
    }



    /**
     * @param $point ['lng'=>'','lat'=>''] array指定点的座标 *
     * @param $circle array ['center'=>['lng'=>'','lat'=>''],'radius'=>''] 中心点和半径
     * @return bool
     * 判断一个座标是否在圆内
     * 思路：判断此点的经纬度到圆心的距离 然后和半径做比较 * 如果此点刚好在圆上 则返回true *
     */
    function is_point_in_circle($point, $circle,$earthR = 6371000){
        $distance = self::distance($point['lat'],$point['lng'],$circle['center']['lat'],$circle['center']['lng'],$earthR);
        if($distance <= $circle['radius']){
            return true;

        }else{
            return false;
        }
    }



}
